import React, { useState, useEffect, useMemo, useCallback, useRef } from 'react';
import { Menu, Spin, message } from 'antd';
import type { MenuProps } from 'antd';
import { useNavigate, useLocation } from 'react-router-dom';
import { useAuthStore } from '@/stores/auth';
import { menuService, UserType } from '@/services/menuService';
import type { Menu as MenuType } from '@/types/rbac';

interface DynamicMenuProps {
  mode?: 'vertical' | 'horizontal' | 'inline';
  theme?: 'light' | 'dark';
  className?: string;
  style?: React.CSSProperties;
  onMenuClick?: (key: string, path: string) => void;
}

/**
 * 动态菜单组件 - 基于V3-Cloud权限模型
 * 1. 根据用户类型自动获取对应菜单
 * 2. 菜单缓存机制，提升性能
 * 3. 自动权限检查和过滤
 * 4. 防止调用失败后持续触发速率限制（in-flight 去重 + 退避冷却）
 */
const DynamicMenu: React.FC<DynamicMenuProps> = ({
  mode = 'inline',
  theme = 'light',
  className,
  style,
  onMenuClick
}) => {
  const navigate = useNavigate();
  const location = useLocation();
  const { user, isAuthenticated, updateUser } = useAuthStore();

  // 使用useMemo实时计算用户类型，避免状态同步延迟
  const userType = useMemo(() => {
    if (!user) return UserType.SYSTEM;
    // 系统用户：统一使用SYSTEM类型
    return UserType.SYSTEM;
  }, [user]);

  // 判断是否为超级管理员 - 使用useMemo优化性能
  const isAdmin = useMemo(() => {
    if (!user || !user.roles || !Array.isArray(user.roles)) {
      return false;
    }
    return user.roles.some(role => {
      if (role && typeof role === 'object' && 'roleKey' in role) {
        const roleKey = (role as any).roleKey;
        return roleKey && (roleKey.includes('SUPER') || roleKey.includes('ADMIN'));
      }
      return false;
    });
  }, [user]);

  const [loading, setLoading] = useState(true);
  const [menuItems, setMenuItems] = useState<MenuProps['items']>([]);
  const [menus, setMenus] = useState<MenuType[]>([]);
  const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
  const [openKeys, setOpenKeys] = useState<string[]>([]);

  const getKeyForMenu = useCallback((m: MenuType) => String((m as any).code || (m as any).id), []);

  /** 递归根据 key 查找菜单 */
  const findMenuByKey = useCallback((list: MenuType[], key: string): MenuType | undefined => {
    for (const m of list) {
      if (getKeyForMenu(m) === key) return m;
      if ((m as any).children && (m as any).children.length) {
        const found = findMenuByKey((m as any).children, key);
        if (found) return found;
      }
    }
    return undefined;
  }, [getKeyForMenu]);

  /** 根据 pathname 查找匹配的菜单及其祖先 keys */
  const findByPathAndAncestors = useCallback((list: MenuType[], pathname: string): { match?: MenuType, ancestorsKeys: string[] } => {
    const ancestors: string[] = [];
    const dfs = (nodes: MenuType[], trail: string[]): MenuType | undefined => {
      for (const n of nodes) {
        const key = getKeyForMenu(n);
        const nextTrail = [...trail, key];
        const nPath = (n as any).path as string | undefined;
        if (nPath && pathname.startsWith(nPath)) {
          ancestors.splice(0, ancestors.length, ...trail);
          return n;
        }
        if ((n as any).children && (n as any).children.length) {
          const found = dfs((n as any).children, nextTrail);
          if (found) return found;
        }
      }
      return undefined;
    };
    const match = dfs(list, []);
    return { match, ancestorsKeys: ancestors };
  }, [getKeyForMenu]);

  /**
   * 防抖/冷却控制，避免失败后高频触发请求导致 Rate Limit
   */
  const fetchCtrl = useRef<{ inFlight: boolean; failureCount: number; cooldownUntil: number }>({
    inFlight: false,
    failureCount: 0,
    cooldownUntil: 0,
  });

  /** 加载用户菜单（带失败退避与冷却） */
  const guardedLoadUserMenus = useCallback(async () => {
    if (!user?.id) return;

    const now = Date.now();
    const ctrl = fetchCtrl.current;

    // in-flight 去重 & 冷却控制
    if (ctrl.inFlight) return;
    if (now < ctrl.cooldownUntil) return;

    // 首次优先使用全局缓存，避免不必要的请求
    if (menus.length === 0 && Array.isArray((user as any)?.menus) && (user as any).menus.length > 0) {
      const cachedMenus = (user as any).menus as MenuType[];
      setMenus(cachedMenus);
      const antdMenuItems = menuService.convertToAntdMenuItems(cachedMenus);
      setMenuItems(antdMenuItems);
      const { match, ancestorsKeys } = findByPathAndAncestors(cachedMenus, location.pathname);
      setSelectedKeys(match ? [getKeyForMenu(match)] : []);
      setOpenKeys(ancestorsKeys);
      setLoading(false);
      return;
    }

    ctrl.inFlight = true;
    setLoading(true);
    try {
      const result = await menuService.getUserMenus(
        userType,
        user.id,
        undefined,
        isAdmin
      );
      if (result.success && result.data && result.data.length > 0) {
        ctrl.failureCount = 0;
        ctrl.cooldownUntil = 0;
        setMenus(result.data);
        const antdMenuItems = menuService.convertToAntdMenuItems(result.data); // 使用后端原始路径，不做前端规范化
        setMenuItems(antdMenuItems);
        // 将菜单写入全局用户信息，供布局面包屑等处使用
        updateUser({ menus: result.data });

        // 根据当前路由初始化选中与展开
        const { match, ancestorsKeys } = findByPathAndAncestors(result.data, location.pathname);
        setSelectedKeys(match ? [getKeyForMenu(match)] : []);
        setOpenKeys(ancestorsKeys);
      } else {
        // 失败退避：指数回退 + 抖动，最长 30s
        ctrl.failureCount += 1;
        const backoff = Math.min(30000, Math.pow(2, ctrl.failureCount) * 1000 + Math.floor(Math.random() * 500));
        ctrl.cooldownUntil = Date.now() + backoff;
        message.error(result.error || '菜单加载失败');
      }
    } catch (e) {
      ctrl.failureCount += 1;
      const backoff = Math.min(30000, Math.pow(2, ctrl.failureCount) * 1000 + Math.floor(Math.random() * 500));
      ctrl.cooldownUntil = Date.now() + backoff;
      message.error('菜单加载异常，请稍后重试');
    } finally {
      ctrl.inFlight = false;
      setLoading(false);
    }
  }, [user?.id, userType, isAdmin, location.pathname, findByPathAndAncestors, getKeyForMenu, menus.length, updateUser]);

  // 仅在鉴权通过且用户ID可用时加载菜单；移除 pathname 等非必要依赖，避免路由变化导致重复请求
  useEffect(() => {
    const hasUserId = !!user?.id;
    const isAuthenticatedCheck = isAuthenticated;
    const shouldLoad = hasUserId && isAuthenticatedCheck;

    if (shouldLoad) {
      guardedLoadUserMenus();
    } else {
      setLoading(false);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isAuthenticated, user?.id]);

  // 路由变化时，仅更新选中与展开，不触发菜单重新加载
  useEffect(() => {
    if (menus.length > 0) {
      const { match, ancestorsKeys } = findByPathAndAncestors(menus, location.pathname);
      setSelectedKeys(match ? [getKeyForMenu(match)] : []);
      setOpenKeys(ancestorsKeys);
    }
  }, [location.pathname, menus, findByPathAndAncestors, getKeyForMenu]);

  /** 处理菜单点击事件 */
  const handleMenuClick = useCallback((menu: MenuType) => {
    const mPath = (menu as any).path as string | undefined;
    if (mPath) {
      onMenuClick?.(getKeyForMenu(menu), mPath);
      navigate(mPath);
    }
  }, [getKeyForMenu, navigate, onMenuClick]);

  /** 处理Ant Design Menu的点击事件 */
  const handleAntdMenuClick = useCallback(({ key }: { key: string }) => {
    const menu = findMenuByKey(menus, key);
    if (menu) {
      handleMenuClick(menu);
    }
  }, [menus, findMenuByKey, handleMenuClick]);

  /** 处理子菜单展开/收起 */
  const handleOpenChange = useCallback((keys: string[]) => {
    setOpenKeys(keys);
  }, []);

  if (loading) {
    return (
      <div style={{ display: 'flex', justifyContent: 'center', padding: '20px' }}>
        <Spin size="small" />
      </div>
    );
  }

  if (!menuItems || menuItems.length === 0) {
    return (
      <div style={{ padding: '20px', textAlign: 'center', color: '#999' }}>
        暂无菜单权限
      </div>
    );
  }

  return (
    <Menu
      mode={mode}
      theme={theme}
      className={className}
      style={style}
      items={menuItems}
      selectedKeys={selectedKeys}
      openKeys={openKeys}
      onClick={handleAntdMenuClick}
      onOpenChange={handleOpenChange}
    />
  );
};

export default DynamicMenu;